package com.whfc.fim.manager.impl;

import com.alibaba.excel.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.whfc.common.constant.QueueConst;
import com.whfc.common.enums.AppWarnModuleType;
import com.whfc.common.exception.BizException;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.third.uni.UniProperties;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.JSONUtil;
import com.whfc.emp.dto.AppFenceDTO;
import com.whfc.emp.entity.AppWorkPlan;
import com.whfc.emp.param.AppFenceListParam;
import com.whfc.emp.service.AppFenceService;
import com.whfc.emp.service.AppWorkPlanService;
import com.whfc.entity.dto.msg.AppMsgToUserDTO;
import com.whfc.entity.dto.msg.PushMsgDTO;
import com.whfc.env.dto.EnvDustDataDTO;
import com.whfc.env.dto.EnvWarnRecordDTO;
import com.whfc.env.service.EnvDataService;
import com.whfc.env.service.EnvWarnDataService;
import com.whfc.fim.dao.*;
import com.whfc.fim.dto.FimMsgToUserDTO;
import com.whfc.fim.dto.FimResultPersonDTO;
import com.whfc.fim.dto.FimResultWarnDTO;
import com.whfc.fim.entity.FimAlgResult;
import com.whfc.fim.entity.FimAlgResultPerson;
import com.whfc.fim.manager.FimResultManager;
import com.whfc.fim.param.FimAlgResultParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author : qzexing
 * @version : 1.0
 * @date : 2021-01-25 19:35
 */
@Slf4j
@Service
public class FimResultManagerImpl implements FimResultManager {

    @Autowired
    private FimAlgResultMapper fimAlgResultMapper;

    @Autowired
    private FimAlgResultImgMapper fimAlgResultImgMapper;

    @Autowired
    private FimWarnRuleMapper fimWarnRuleMapper;

    @Autowired
    private FimWarnRuleUserMapper fimWarnRuleUserMapper;

    @Autowired
    private FimWarnRuleChannelMapper fimWarnRuleChannelMapper;

    @Autowired
    private FimAlgResultPersonMapper fimAlgResultPersonMapper;

    @DubboReference(interfaceClass = AppFenceService.class, version = "1.0.0", timeout = 10 * 1000)
    private AppFenceService appFenceService;

    @DubboReference(interfaceClass = AppWorkPlanService.class, version = "1.0.0", timeout = 30000)
    private AppWorkPlanService appWorkPlanService;

    @DubboReference(interfaceClass = EnvDataService.class, version = "1.0.0")
    private EnvDataService envDataService;

    @DubboReference(interfaceClass = EnvWarnDataService.class, version = "1.0.0")
    private EnvWarnDataService envWarnDataService;

    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private UniProperties uniProperties;

    @Override
    public FimResultWarnDTO uploadAlgResult(FimAlgResultParam algResultParam) throws BizException {
        Integer deptId = algResultParam.getDeptId();
        String deviceName = algResultParam.getDeviceName();
        Integer algCheckType = algResultParam.getAlgCheckType();
        String algCheckTypeName = algResultParam.getAlgCheckTypeName();
        Date time = algResultParam.getTime();
        boolean isValidAlarm = false;
        Integer fimWarnRuleId = fimWarnRuleMapper.selectByDeptIdAndType(deptId, algCheckType);
        // 查找消息接收人信息
        List<FimMsgToUserDTO> userDtoList = fimWarnRuleUserMapper.selectByWarnRuleId(fimWarnRuleId);
        if (algCheckType != null && algCheckType == 515){
            // 视频监控报警-区域入侵
            isValidAlarm = handleYushiAreaIntrusionAlarm(algResultParam, userDtoList);
            if (!isValidAlarm){
                throw new BizException(ResultEnum.FAILURE.getCode(), "区域入侵预警未检测到深坑作业");
            }
        }
        //保存算法结果
        FimAlgResult fimAlgResult = new FimAlgResult();
        fimAlgResult.setDeptId(deptId);
        fimAlgResult.setDeviceId(algResultParam.getDeviceId());
        fimAlgResult.setDeviceName(deviceName);
        fimAlgResult.setDeviceVendor(algResultParam.getDeviceVendor());
        fimAlgResult.setAlgCheckType(algCheckType);
        fimAlgResult.setAlgCheckTypeName(algCheckTypeName);
        fimAlgResult.setTime(time);
        //获取图片列表
        List<String> algResultImgList = algResultParam.getAlgResultImgList();
        if (algResultImgList != null && algResultImgList.size() > 0) {
            //设置封面
            fimAlgResult.setSnapshotUrl(algResultImgList.get(0));
        }
        fimAlgResultMapper.insertSelective(fimAlgResult);
        //获取报警记录ID
        Integer resultId = fimAlgResult.getId();
        //保存人员信息
        List<FimResultPersonDTO> personDTOList = algResultParam.getPersonList();
        if (personDTOList != null && !personDTOList.isEmpty()) {
            List<FimAlgResultPerson> personList = new ArrayList<>();
            for (FimResultPersonDTO fimResultPersonDTO : personDTOList) {
                FimAlgResultPerson fimAlgResultPerson = new FimAlgResultPerson();
                BeanUtils.copyProperties(fimResultPersonDTO, fimAlgResultPerson);
                fimAlgResultPerson.setAlgResultId(resultId);
                personList.add(fimAlgResultPerson);
            }
            fimAlgResultPersonMapper.batchInsert(personList);
        }
        //保存图片信息
        if (algResultImgList != null && algResultImgList.size() > 0) {
            fimAlgResultImgMapper.batchInsert(resultId, algResultImgList,algResultParam.getBase64());
        }
        //生成报警需要的信息
        FimResultWarnDTO fimResultWarnDTO = new FimResultWarnDTO();
        fimResultWarnDTO.setResultId(resultId);
        fimResultWarnDTO.setDeptId(deptId);
        fimResultWarnDTO.setAlgCheckType(algCheckType);
        fimResultWarnDTO.setDeviceId(algResultParam.getDeviceId());
        fimResultWarnDTO.setTime(time);

        // 查找消息接收方式
        List<Integer> msgChannelList = fimWarnRuleChannelMapper.selectMsgChannelByWarnRuleId(fimWarnRuleId);
        fimResultWarnDTO.setUserDtoList(userDtoList);
        fimResultWarnDTO.setMsgChannelList(msgChannelList);
//        if (isValidAlarm) {
//            sendAlarmMQ(algResultParam, resultId, userDtoList);
//        }
        return fimResultWarnDTO;
    }

    /**
     * 处理宇视监控区域入侵报警
     * @param algResultParam 算法结果参数
     * @param userDtoList 用户列表
     */
    private boolean handleYushiAreaIntrusionAlarm(FimAlgResultParam algResultParam, List<FimMsgToUserDTO> userDtoList) {
        boolean isValidAlarm = false;
        try {
            log.info("开始处理算法结果消息: {}", algResultParam.getDeviceId(), algResultParam.getDeviceName());
            // 1. 依据algResultParam.getDeviceId()关联app_fence表中的fvs_device_ids字段查询电子围栏
            Integer deviceId = algResultParam.getDeviceId();
            List<AppFenceDTO> appFenceDTOS = appFenceService.listByFvsDeviceId(deviceId);

            if (appFenceDTOS == null || appFenceDTOS.isEmpty()) {
                return isValidAlarm; // 没有关联的电子围栏，不处理
            }
            // 2. 依据查询出来的电子围栏ID关联工作计划app_work_plan表中的work_area_id查询工作计划
            for (AppFenceDTO appFenceDTO : appFenceDTOS) {
                List<AppWorkPlan> appWorkPlans = appWorkPlanService.listValidPlansByWorkAreaAndDate(appFenceDTO.getId(), DateUtil.formatDateTime(new Date()));
                for (AppWorkPlan workPlan : appWorkPlans) {
                    // 3. 如果当前工作计划id_deep_work==1为深坑作业任务
                    if (workPlan.getIsDeepWork() != null && workPlan.getIsDeepWork() == 1) {
                        String envDustIds = workPlan.getEnvDustIds();
                        // 4. 依据工作计划表中的env_dust_ids查询判断是否有5分钟内的气体数据
                        if (StringUtils.isNotBlank(envDustIds)) {
                            boolean hasRecentDustData = checkRecentDustData(envDustIds);
                            if (!hasRecentDustData) {
                                // 如果没有5分钟内的气体数据，则本次为有效报警
                                isValidAlarm = true;
                                break;
                            }
                        }

                        // 5. 或者是否有对应设备的未处置的气体报警记录
                        if (!isValidAlarm && StringUtils.isNotBlank(envDustIds)) {
                            boolean hasUnhandledAlarm = checkUnhandledAlarm(envDustIds);
                            if (hasUnhandledAlarm) {
                                // 如果有未处理的报警记录，则本次为有效报警
                                isValidAlarm = true;
                                break;
                            }
                        }
                    }
                }
            }
            return isValidAlarm;
            // 6. 如果本次为有效报警则发送报警MQ
//            if (isValidAlarm) {
//                sendAlarmMQ(algResultParam, resultId, userDtoList);
//            }
        } catch (Exception e) {
            // 记录错误日志，但不影响主流程
            log.error("处理宇视监控区域入侵报警失败: {}", e.getMessage());
        }
        return isValidAlarm;
    }

    /**
     * 检查是否有5分钟内的气体数据
     */
    private boolean checkRecentDustData(String envDustIds) {
        // 解析设备ID列表
        String[] dustIds = envDustIds.split(",");
        Date fiveMinutesAgo = new Date(System.currentTimeMillis() - 5 * 60 * 1000);
        boolean flag = false;
        for (String dustIdStr : dustIds) {
            try {
                Integer dustId = Integer.parseInt(dustIdStr.trim());
                List<EnvDustDataDTO> dustDataLog = envDataService.getDustDataLog(dustId, fiveMinutesAgo, new Date());
                if (dustDataLog != null && !dustDataLog.isEmpty()){
                    flag = true;
                }
            } catch (NumberFormatException e) {
                log.error("查询设备:{} 历史信息失败: {}",dustIdStr, e.getMessage());
            }
        }
        return flag;
    }

    /**
     * 检查是否有未处理的气体报警记录
     */
    private boolean checkUnhandledAlarm(String envDustIds) {
        // 解析设备ID列表
        String[] dustIds = envDustIds.split(",");

        for (String dustIdStr : dustIds) {
            try {
                Integer dustId = Integer.parseInt(dustIdStr.trim());
                // 查询未处理的报警记录
                PageData<EnvWarnRecordDTO> recordDTOPageData = envWarnDataService.getUnhandledGasWarnRecords(dustId, null, null, 1, 1);

                // int count = envAlarmRecordMapper.countUnhandledAlarm(dustId);
                 if (recordDTOPageData != null && recordDTOPageData.getTotal() > 0) {
                     return true;
                 }
            } catch (NumberFormatException e) {
                // 忽略格式错误的ID
                log.error("查询设备:{} 是否有未处理的气体报警记录失败: {}",dustIdStr, e.getMessage());
            }
        }

        return false;
    }

    /**
     * 发送报警MQ消息
     */
    private void sendAlarmMQ(FimAlgResultParam algResultParam, Integer resultId,
                             List<FimMsgToUserDTO> userDtoList) {
        try {
//            Map<String, Object> msgDTO = new HashMap<>();
//            msgDTO.put("resultId", resultId);
//            msgDTO.put("deviceId", algResultParam.getDeviceId());
//            msgDTO.put("deviceName", algResultParam.getDeviceName());
//            msgDTO.put("algCheckType", algResultParam.getAlgCheckType());
//            msgDTO.put("algCheckTypeName", algResultParam.getAlgCheckTypeName());
//            msgDTO.put("time", algResultParam.getTime());
//            msgDTO.put("workPlanId", workPlan.get("id"));
//            msgDTO.put("userList", userDtoList);
//            msgDTO.put("alarmType", "yushi_area_intrusion");
//            msgDTO.put("description", "宇视监控区域入侵报警 - 深坑作业安全预警");

            String content = String.format("监控设备{}【{}】触发区域入侵警报，时间:{}", algResultParam.getDeviceName(), algResultParam.getDeviceId(), algResultParam.getTime());
            List<Integer> msgChannelList = Arrays.asList(3, 1); // 3=后台(PC), 1=小程序(APP)
            List<AppMsgToUserDTO> msgToUserDTOS = new ArrayList<>();
            for (FimMsgToUserDTO dto : userDtoList){
                AppMsgToUserDTO userDTO = new AppMsgToUserDTO();
                BeanUtils.copyProperties(dto, userDTO);
                msgToUserDTOS.add(userDTO);
            }
            PushMsgDTO pushMsgDTO = new PushMsgDTO();
            pushMsgDTO.setContent(content);
            pushMsgDTO.setDeptId(algResultParam.getDeptId());
            pushMsgDTO.setModuleType(AppWarnModuleType.EMP.value());
            pushMsgDTO.setMsgChannelList(msgChannelList);
            pushMsgDTO.setMsgObjectId(String.valueOf(resultId));
            pushMsgDTO.setTitle(algResultParam.getAlgCheckTypeName());
            pushMsgDTO.setToUserList(msgToUserDTOS);
            pushMsgDTO.setTime(algResultParam.getTime());
            amqpTemplate.convertAndSend(QueueConst.PUSH_MSG_EXCHANGE, "", JSONObject.toJSONString(pushMsgDTO));

        } catch (Exception e) {
            System.err.println("发送报警MQ失败: " + e.getMessage());
            log.error("{}触发报警{} 发送消息失败: {}", algResultParam.getDeviceId(), resultId, e.getMessage());
        }
    }
}
